from collections import OrderedDict
from django.forms.formsets import formset_factory
from django.shortcuts import render, redirect, HttpResponse
from django.conf import settings
from django.utils.module_loading import import_string
from rbac.forms.menu import MenuModelForm, SecondMenuModelForm, PermissionModelForm, MultiAddPermissionForm, \
    MultiEditPermissionForm
from rbac.models import Permission, Menu, Role
from rbac.service.routers import get_all_url_dict
from rbac.service.urls import memory_reverse


def menu_list(request):
    """
    菜单列表
    :param request:
    :return:
    """
    menu_queryset = Menu.objects.all()
    menu_id = request.GET.get('mid')
    second_menu_id = request.GET.get('sid')
    menu_exists = Menu.objects.filter(id=menu_id).exists()

    if not menu_exists:
        menu_id = None

    second_menu_exist = Permission.objects.filter(id=second_menu_id).exists()
    if not second_menu_exist:
        second_menu_id = None

    if menu_id:
        second_menu = Permission.objects.filter(menu_id=menu_id)
    else:
        second_menu = []
    if second_menu_id:
        permissions = Permission.objects.filter(pid_id=second_menu_id)
    else:
        permissions = []
    return render(
        request,
        'rbac/menu_list.html',
        {
            'menus': menu_queryset,
            'menu_id': menu_id,
            'second_menu': second_menu,
            'second_menu_id': second_menu_id,
            'permissions': permissions
        }
    )


def menu_add(request):
    """
    添加菜单
    :param request:
    :return:
    """

    if request.method == "GET":
        form = MenuModelForm()
        return render(request, 'rbac/change.html', {'form': form})

    form = MenuModelForm(data=request.POST)
    if form.is_valid():
        form.save()
        url = memory_reverse(request, "rbac:menu_list")
        return redirect(url)
    return render(request, 'rbac/change.html', {'form': form})


def menu_edit(request, pk):
    """
    菜单编辑
    :param request:
    :param pk:
    :return:
    """
    menu_obj = Menu.objects.filter(id=pk).first()
    if not menu_obj:
        return HttpResponse("数据不存在")
    if request.method == 'GET':
        form = MenuModelForm(instance=menu_obj)
        return render(request, "rbac/change.html", locals())
    form = MenuModelForm(instance=menu_obj, data=request.POST)
    if form.is_valid():
        form.save()
        url = memory_reverse(request, "rbac:menu_list")
        return redirect(url)
    return render(request, "rbac/change.html", locals())


def menu_del(request, pk):
    """
    删除菜单
    :param request:
    :param pk:
    :return:
    """
    obj = Menu.objects.filter(id=pk).first()
    url = memory_reverse(request, "rbac:menu_list")
    if not obj:
        return HttpResponse("数据不存在")
    if request.method == 'GET':
        return render(request, 'rbac/delete.html', {'cancel_url': url})

    obj.delete()
    return redirect(url)


def second_menu_add(request, menu_id):
    """
    添加二级菜单
    :param request:
    :param menu_id: 菜单ID
    :return:
    """
    menu_obj = Menu.objects.filter(id=menu_id).first()

    if request.method == "GET":
        form = SecondMenuModelForm(initial={'menu': menu_obj})
        return render(request, 'rbac/change.html', {'form': form})

    form = SecondMenuModelForm(data=request.POST)
    if form.is_valid():
        form.save()
        url = memory_reverse(request, "rbac:menu_list")
        return redirect(url)
    return render(request, 'rbac/change.html', {'form': form})


def second_menu_edit(request, pk):
    """
    编辑二级菜单
    :param request:
    :param pk: 权限ID
    :return:
    """
    second_menu_obj = Permission.objects.filter(id=pk).first()
    if not second_menu_obj:
        return HttpResponse("数据不存在")
    if request.method == 'GET':
        form = SecondMenuModelForm(instance=second_menu_obj)
        return render(request, "rbac/change.html", locals())
    form = SecondMenuModelForm(instance=second_menu_obj, data=request.POST)
    if form.is_valid():
        form.save()
        url = memory_reverse(request, "rbac:menu_list")
        return redirect(url)
    return render(request, "rbac/change.html", locals())


def second_menu_del(request, pk):
    """
    删除菜单
    :param request:
    :param pk：二级菜单ID
    :return:
    """
    obj = Permission.objects.filter(id=pk).first()
    url = memory_reverse(request, "rbac:menu_list")
    if not obj:
        return HttpResponse("数据不存在")
    if request.method == 'GET':
        return render(request, 'rbac/delete.html', {'cancel_url': url})

    obj.delete()
    return redirect(url)


def permission_add(request, second_menu_id):
    """
    添加权限
    :param request:
    :param second_menu_id: 二级菜单ID
    :return:
    """
    if request.method == "GET":
        form = PermissionModelForm()
        return render(request, 'rbac/change.html', {'form': form})
    form = PermissionModelForm(data=request.POST)
    if form.is_valid():
        second_menu_obj = Permission.objects.filter(id=second_menu_id).first()
        if not second_menu_obj:
            return HttpResponse('二级菜单不存在，请重新输入')
        form.instance.pid = second_menu_obj
        form.save()
        return redirect(memory_reverse(request, 'rbac:menu_list'))
    return render(request, 'rbac/change.html', {'form': form})


def permission_edit(request, pk):
    """
    编辑权限
    :param request:
    :param pk: 权限ID
    :return:
    """
    permission_obj = Permission.objects.filter(id=pk).first()
    if not permission_obj:
        return HttpResponse('权限不存在，请重新输入')
    if request.method == 'GET':
        form = PermissionModelForm(instance=permission_obj)
        return render(request, 'rbac/change.html', {'form': form})
    form = PermissionModelForm(instance=permission_obj, data=request.POST)
    if form.is_valid():
        form.save()
        return redirect(memory_reverse(request, 'rbac:menu_list'))
    return render(request, 'rbac/change.html', {'form': form})


def permission_del(request, pk):
    """
    删除权限
    :param request:
    :param pk:
    :return:
    """

    obj = Permission.objects.filter(id=pk).first()
    url = memory_reverse(request, 'rbac:menu_list')
    if not obj:
        return HttpResponse('权限不存在，请重新输入')
    if request.method == "GET":
        return render(request, 'rbac/delete.html', {'cancel_url': url})
    obj.delete()
    return redirect(url)


def multi_permissions_del(request, pk):
    """

    :param request:
    :param pk:
    :return:
    """
    obj = Permission.objects.filter(id=pk).first()
    url = memory_reverse(request, 'rbac:multi_permission')
    if not obj:
        return HttpResponse('权限不存在，请重新输入')
    if request.method == "GET":
        return render(request, 'rbac/delete.html', {'cancel_url': url})
    obj.delete()
    return redirect(url)


def multi_permissions(request):
    """
    批量操作
    :param request:
    :return:
    """
    operate_type = request.GET.get('type')
    generate_formset_class = formset_factory(MultiAddPermissionForm, extra=0)
    generate_formset = None
    if request.method == 'POST' and operate_type == 'generate':
        formset = generate_formset_class(data=request.POST)
        if formset.is_valid():
            post_row_list = formset.cleaned_data
            new_obj_list = []
            has_error = False
            for i in range(0, formset.total_form_count()):
                row_dict = post_row_list[i]
                try:
                    new_obj = Permission(**row_dict)
                    for key, value in row_dict.items():
                        setattr(new_obj, key, value)
                    new_obj.validate_unique()
                    new_obj_list.append(new_obj)
                except Exception as e:
                    formset.errors[i].update(e)
                    generate_formset = formset
                    has_error = True
            if not has_error:
                Permission.objects.bulk_create(new_obj_list, batch_size=100)
        else:
            generate_formset = formset
    update_formset_class = formset_factory(MultiEditPermissionForm, extra=0)
    update_formset = None
    if request.method == 'POST' and operate_type == 'update':
        formset = update_formset_class(data=request.POST)
        if formset.is_valid():
            post_row_list = formset.cleaned_data
            for i in range(0, formset.total_form_count()):
                row_dict = post_row_list[i]
                if not row_dict:
                    continue
                permission_id = row_dict.pop('id')
                try:
                    row_obj = Permission.objects.filter(id=permission_id).first()
                    for key, value in row_dict.items():
                        setattr(row_obj, key, value)
                    row_obj.validate_unique()
                    # print(row_obj.menu, row_obj.pid)
                    row_obj.save()
                except Exception as e:
                    formset.errors[i].update(e)
                    update_formset = formset
        else:
            update_formset = formset
    # ###########自动发现项目中的所有路由###################
    # ###########自动发现项目中的所有路由###################
    url_ordered_dict = get_all_url_dict()
    route_name_set = set(url_ordered_dict.keys())
    # ###########从数据库中取出所有权限,###################
    permissions_queryset = Permission.objects.all().values('id', 'title', 'url', 'name', 'menu_id', 'pid_id')
    permissions_dict = OrderedDict()
    permission_name_set = set()
    for row in permissions_queryset:
        permission_name_set.add(row['name'])
        permissions_dict[row['name']] = row
    for name, value in permissions_dict.items():
        route_row_dict = url_ordered_dict.get(name)
        if not route_row_dict:
            continue
        if value['url'] != route_row_dict['url']:
            value['url'] = '路由和数据库中的url不一致,数据库url:%s,路由中是:%s' % (value['url'], route_row_dict['url'])
    # ##########自动发现有，数据库中没有，待增加权限##########
    if not generate_formset:
        generate_name_list = route_name_set - permission_name_set
        generate_formset = generate_formset_class(
            initial=[row_dict for name, row_dict in url_ordered_dict.items() if name in generate_name_list])
    # ##########待删除权限##########################
    delete_name_list = permission_name_set - route_name_set
    delete_list = [row_dict for name, row_dict in permissions_dict.items() if name in delete_name_list]

    # ##########取集合的交集，待更新权限#############
    if not update_formset:
        update_name_list = route_name_set & permission_name_set
        update_formset = update_formset_class(
            initial=[row_dict for name, row_dict in permissions_dict.items() if name in update_name_list]
        )
    return render(
        request,
        'rbac/multi_permissions.html',
        {
            'generate_formset': generate_formset,
            'delete_list': delete_list,
            'update_formset': update_formset
        }
    )


def distribute_permissions(request):
    """
    权限分配
    :param request:
    :return:
    """
    user_id = request.GET.get('uid')
    user_model_class = import_string(settings.RBAC_USER_MODEL_CLASS)
    user_object = user_model_class.objects.filter(id=user_id).first()
    if not user_object:
        user_id = None

    role_id = request.GET.get('rid')
    role_object = Role.objects.filter(id=role_id).first()
    if not role_object:
        role_id = None

    # 保存角色
    if request.method == "POST" and request.POST.get('type') == 'role':
        if not user_object:
            return HttpResponse('用户不存在，请重新选择')
        role_id_list = request.POST.getlist('roles')
        user_object.roles.set(role_id_list)
    if request.method == "POST" and request.POST.get('type') == 'permission':
        if not role_object:
            return HttpResponse("角色不存在，请重新选择")
        perrmission_id_list = request.POST.getlist('permissions')
        role_object.permissions.set(perrmission_id_list)
        print(perrmission_id_list)

    # 获取当前用户的所有角色
    if user_id:
        user_has_roles = user_object.roles.all()
    else:
        user_has_roles = []
    user_has_roles_dict = {item.id: None for item in user_has_roles}

    # 获取当前用户的所有权限
    # 如果选中了角色，优选选中角色拥有的权限
    if role_object:
        user_has_permissions = role_object.permissions.all()
        user_has_permissions_dict = {item.id: None for item in user_has_permissions}
    elif user_object:
        user_has_permissions = user_object.roles.filter(permissions__isnull=False).values('permissions__id').distinct()
        user_has_permissions_dict = {item['permissions__id']: None for item in user_has_permissions}
    else:
        user_has_permissions_dict = {}

    # 获取所有用户
    all_user_list = user_model_class.objects.all()
    # 获取所有角色
    all_role_list = Role.objects.all()

    all_menu_dict = {}
    # 获取所有菜单
    all_menu_list = Menu.objects.values('id', 'title')
    for item in all_menu_list:
        item['children'] = []
        all_menu_dict[item['id']] = item
    # 所有二级菜单
    all_second_menu_list = Permission.objects.filter(menu_id__isnull=False).values('id', 'title', 'menu_id')
    all_second_menu_dict = {}
    for row in all_second_menu_list:
        row['children'] = []
        all_second_menu_dict[row['id']] = row
        menu_id = row['menu_id']
        all_menu_dict[menu_id]['children'].append(row)

    # 所有三级菜单(不能做菜单的权限）

    all_permission_list = Permission.objects.filter(pid_id__isnull=False).values('id', 'title', 'pid')

    for row in all_permission_list:
        pid = row['pid']
        if not pid:
            continue
        all_second_menu_dict[pid]['children'].append(row)
    return render(
        request,
        'rbac/distribute_permissions.html',
        {'user_list': all_user_list,
         'role_list': all_role_list,
         'all_menu_list': all_menu_list,
         'uid': user_id,
         'user_has_roles_dict': user_has_roles_dict,
         'user_has_permissions_dict': user_has_permissions_dict,
         'role_id': role_id
         }
    )
